<?php  !defined('BASE_ROOT') && exit ( 'Access Denied!' );
class Cache {
	/**
	 * 默认的数据生存期
	 */
	public $limit_time = null;
	/**
	 * 模型对象
	 */
	private $model_obj = null;
	/** 
	 * 初始化缓存对象
	 */
    public function init(& $obj, $args){
		$this->model_obj = $obj;
		if($args == null){
			$this->limit_time = get_config('CacheTime');
		}else{
			$this->limit_time = $args;
		}
		return $this;
	}
	/** 
	 * 魔术函数，支持多重函数式使用类的方法
	 */
	public function __call($func_name, $func_args){
		if( -1 == $this->limit_time ){
			return $this->clear( $this->model_obj , $func_name, $func_args);
		}
		return $this->cache_obj( $this->model_obj , $func_name, $func_args, $this->limit_time);
	}
	/** 
	 * 执行Model子类对象的方法，并对返回结果进行缓存。
	 *
	 * @param obj    引用的Model子类对象
	 * @param func_name    需要执行的函数名称
	 * @param func_args    函数的参数
	 * @param limit_time    缓存生存时间
	 */
	public function cache_obj(& $obj, $func_name, $func_args = null, $limit_time = null ){
		$cache_id = get_class($obj) . md5($func_name);
		if( null != $func_args )$cache_id .= md5(serialize($func_args));
		if( $cache_file = $this->cacheAccess('r', "cai_cache_{$cache_id}") ){
			return unserialize( $cache_file );
		}
		$run_result = call_user_func_array(array($obj, $func_name), $func_args);
		$this->cacheAccess('w', "cai_cache_{$cache_id}", serialize($run_result), $limit_time);
		if( $cache_list = $this->cacheAccess('r', 'cai_cache_list') ){
			$cache_list = explode("\n",$cache_list);
			if( ! in_array( $cache_id, $cache_list ) )$this->cacheAccess('w', 'cai_cache_list', join("\n", $cache_list) . $cache_id . "\n");
		}else{
			$this->cacheAccess('w', 'cai_cache_list', $cache_id . "\n");
		}
		return $run_result;
	}
	/** 
	 * 清除单个函数缓存的数据
	 *
	 * @param obj    引用的Model子类对象
	 * @param func_name    需要执行的函数名称
	 * @param func_args    函数的参数，在默认不输入参数的情况下，将清除全部该函数生成的缓存。
	 * 如果func_args有设置，将只会清除该参数产生的缓存。
	 */
	public function clear(& $obj, $func_name, $func_args = null){
		$cache_id = get_class($obj) . md5($func_name);
		if( null != $func_args )$cache_id .= md5(serialize($func_args));
		if( $cache_list = $this->cacheAccess('r', 'cai_cache_list') ){
			$cache_list = explode("\n",$cache_list);
			$new_list = '';
			foreach( $cache_list as $single_item ){
				if( $single_item == $cache_id || ( null == $func_args && substr($single_item,0,strlen($cache_id)) == $cache_id ) ){
					$this->cacheAccess('c', "cai_cache_{$single_item}");
				}else{
					$new_list .= $single_item. "\n";
				}
			}
			$this->cacheAccess('w', 'cai_cache_list', substr($new_list,0,-1));
		}

		$run_result = call_user_func_array(array($obj, $func_name), $func_args);
		return $run_result;
	}
	/**
	 * 开启缓存
	 *
	 * @access public
	 */
	public function open($limit_time = null) {
		$CAI =& get_instance();
		$CAI->_cache = true;
		if($limit_time != null){
			$CAI->_cachetime = $limit_time; 
		}
	}
	/**
	 * 关闭缓存
	 *
	 * @access public
	 */
	public function close() {
		$CAI =& get_instance();
		$CAI->_cache = false;
	}
	/** 
	 * 清除全部函数缓存的数据
	 *
	 */
	public function clearAll(){
		if( $cache_list = $this->cacheAccess('r', 'cai_cache_list') ){
			$cache_list = explode("\n",$cache_list);
			foreach( $cache_list as $single_item )$this->cacheAccess('c', "cai_cache_{$single_item}");
			$this->cacheAccess('c', 'cai_cache_list');
		}
		return TRUE;
	}

	/**
	 * cacheAccess 数据缓存及存取程序
	 * 
	 * @param method    数据存取模式，取值"w"为存入数据，取值"r"读取数据，取值"c"为删除数据
	 * @param name    标识数据的名称
	 * @param value    存入的值，在读取数据和删除数据的模式下均为NULL
	 * @param limit_time    变量的生存时间，默认为永久保存
	 */
	public function cacheAccess($method, $name, $value = NULL, $limit_time = -1)
	{
		$sfile = BASE_CACHE.'/'.md5($name).".php";
		if('w' == $method){ // 写数据
			$limit_time = ( -1 == $limit_time ) ? '300000000' : $limit_time;
			$value = '<?php die();?>'.( time() + $limit_time ).serialize($value);
			return file_put_contents($sfile, $value);
		}elseif('c' == $method){ // 清除数据
			return @unlink($sfile);
		}else{ // 读数据
			if( !is_readable($sfile) )return FALSE;
			$arg_data = file_get_contents($sfile);
			if( substr($arg_data, 14, 10) < time() ){
				$this->cacheAccess('c', $name);
				return FALSE;
			}
			return unserialize(substr($arg_data, 24));
		}
	}
}